﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

Процедура ЗагрузитьКонтурИзСообщения(КомпонентыОбмена, Header) Экспорт
	
	Если Не Header.Установлено("SynchronizationContour") Тогда
		Возврат;
	КонецЕсли;
		
	Если Header.SynchronizationContour <> Неопределено Тогда
		
		Дерево = Новый ДеревоЗначений;
		Дерево.Колонки.Добавить("КодУзла");
		Дерево.Колонки.Добавить("КодУзлаКорреспондента");
		Дерево.Колонки.Добавить("ИмяУзла");
		Дерево.Колонки.Добавить("ИмяУзлаКорреспондента");
		Дерево.Колонки.Добавить("ПоследнееОбновление");
		Дерево.Колонки.Добавить("Префикс");
		Дерево.Колонки.Добавить("Зацикливание");
		
		Для Каждого Node Из Header.SynchronizationContour.Node Цикл
			
			НовыйУзел = Дерево.Строки.Добавить();
			НовыйУзел.КодУзла = Node.Code;
			НовыйУзел.ИмяУзла = ПолучитьСтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзBase64Строки(Node.Name));
			НовыйУзел.ПоследнееОбновление = Node.LastUpdate;
			НовыйУзел.Префикс = Node.Prefix;
				
			Для Каждого CorrNode Из Node.CorrNodes.CorrNode Цикл
					
				НовыйКоррУзел = НовыйУзел.Строки.Добавить();
				НовыйКоррУзел.КодУзлаКорреспондента = CorrNode.Code;
				НовыйКоррУзел.ИмяУзлаКорреспондента = ПолучитьСтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзBase64Строки(CorrNode.Name));
				НовыйКоррУзел.Зацикливание = CorrNode.Looping;
				
			КонецЦикла;
			
		КонецЦикла;
		
		ИмяПланаОбмена = КомпонентыОбмена.УзелКорреспондента.Метаданные().Имя;
		
		ОбновитьКонтурИзДерева(Дерево, ИмяПланаОбмена);
		ЗаменитьПрефиксы();
		ПроверитьЗацикливание(ИмяПланаОбмена);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ВыгрузитьКонтурВСообщение(Header, ИмяПланаОбмена) Экспорт
	
	ОбновитьКонтур(ИмяПланаОбмена);
	
	КонтурСинхронизации = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "SynchronizationContour"));
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Контур.ИмяУзла КАК ИмяУзла,
		|	Контур.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента,
		|	Контур.ПоследнееОбновление КАК ПоследнееОбновление,
		|	Контур.Префикс КАК Префикс,
		|	Контур.Зацикливание КАК Зацикливание
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ИТОГИ
		|	МАКСИМУМ(ИмяУзла),
		|	МАКСИМУМ(ПоследнееОбновление),
		|	МАКСИМУМ(Префикс)
		|ПО
		|	КодУзла";
	
	ВыборкаПоУзлам = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Пока ВыборкаПоУзлам.Следующий() Цикл
		
		Узел = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Node"));
		Узел.Code 		= ВыборкаПоУзлам.КодУзла;
		Узел.Name 		= ПолучитьBase64СтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзСтроки(ВыборкаПоУзлам.ИмяУзла));
		Узел.LastUpdate = ВыборкаПоУзлам.ПоследнееОбновление;
		Узел.Prefix 	= ВыборкаПоУзлам.Префикс;
		
		КоррУзлы = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "CorrNodes"));
		
		ВыборкаПоКоррУзлам = ВыборкаПоУзлам.Выбрать();
		Пока ВыборкаПоКоррУзлам.Следующий() Цикл	
			
			КоррУзел = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "CorrNode"));
			КоррУзел.Code = ВыборкаПоКоррУзлам.КодУзлаКорреспондента;
			КоррУзел.Name = ПолучитьBase64СтрокуИзДвоичныхДанных(ПолучитьДвоичныеДанныеИзСтроки(ВыборкаПоКоррУзлам.ИмяУзлаКорреспондента));
			КоррУзел.Looping = ВыборкаПоКоррУзлам.Зацикливание;
			КоррУзлы.CorrNode.Добавить(КоррУзел);
			
		КонецЦикла;
		
		Если КоррУзлы.CorrNode.Количество() > 0 Тогда
			Узел.CorrNodes = КоррУзлы;
		Иначе
			Узел.CorrNodes = Неопределено;
		КонецЕсли;
		
		КонтурСинхронизации.Node.Добавить(Узел);
		
	КонецЦикла;

	Если КонтурСинхронизации.Node.Количество() > 0 Тогда
		Header.SynchronizationContour = КонтурСинхронизации;
	Иначе
		Header.SynchronizationContour = Неопределено;	
	КонецЕсли;
		
КонецПроцедуры

Процедура ОбновитьКонтур(ИмяПланаОбмена) Экспорт

	ТекстЗапроса = 
		"ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.Префикс КАК Префикс
		|ПОМЕСТИТЬ ВТ_Префиксы
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	Контур.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Контур.ИмяУзла КАК ИмяУзла,
		|	Контур.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента,
		|	Контур.ПоследнееОбновление КАК ПоследнееОбновление
		|ПОМЕСТИТЬ ВТ_Контур
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.УзелИнформационнойБазы <> НЕОПРЕДЕЛЕНО
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	Узлы.Ссылка КАК Ссылка,
		|	ЕСТЬNULL(ВТ_Префиксы.КодУзла, Узлы.Код) КАК Код,
		|	Узлы.Наименование КАК Наименование
		|ПОМЕСТИТЬ ВТ_Узлы
		|ИЗ
		|	&ПланОбмена КАК Узлы
		|		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Префиксы КАК ВТ_Префиксы
		|		ПО Узлы.Код = ВТ_Префиксы.Префикс
		|ГДЕ
		|	Узлы.Ссылка <> &ЭтотУзел
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ИСТИНА КАК ЕстьУдаление
		|ПОМЕСТИТЬ ВТ_ЕстьУдаление
		|ИЗ
		|	ВТ_Контур КАК ВТ_Контур
		|		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Узлы КАК ВТ_Узлы
		|		ПО ВТ_Контур.УзелИнформационнойБазы = ВТ_Узлы.Ссылка
		|ГДЕ
		|	ВТ_Узлы.Ссылка ЕСТЬ NULL
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ВТ_Узлы.Ссылка КАК Ссылка,
		|	ВТ_Узлы.Код КАК Код,
		|	ВТ_Узлы.Наименование КАК Наименование,
		|	ВТ_Контур.КодУзла КАК КодУзла,
		|	ВТ_Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	ВТ_Контур.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	ВЫБОР
		|		КОГДА НЕ ВТ_Контур.УзелИнформационнойБазы ЕСТЬ NULL
		|				И НЕ ВТ_Узлы.Ссылка ЕСТЬ NULL
		|				И (ВТ_Контур.КодУзла <> &КодЭтогоУзла
		|					ИЛИ ВТ_Контур.ИмяУзла <> &НаименованиеЭтогоУзла
		|					ИЛИ ВТ_Контур.КодУзлаКорреспондента <> ВТ_Узлы.Код
		|					ИЛИ ВТ_Контур.ИмяУзлаКорреспондента <> ВТ_Узлы.Наименование)
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК ОбновитьРеквизиты,
		|	ВЫБОР
		|		КОГДА ВТ_Контур.УзелИнформационнойБазы ЕСТЬ NULL
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК ДобавитьУзелВКонтур,
		|	ВЫБОР
		|		КОГДА ВТ_Узлы.Ссылка ЕСТЬ NULL
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК УдалитьУзелИзКонтура,
		|	ВЫБОР
		|		КОГДА ЕСТЬNULL(ВТ_ЕстьУдаление.ЕстьУдаление, ЛОЖЬ)
		|			ТОГДА ИСТИНА
		|		ИНАЧЕ ЛОЖЬ
		|	КОНЕЦ КАК УстановитьПоследнееОбновление
		|ИЗ
		|	ВТ_Контур КАК ВТ_Контур
		|		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Узлы КАК ВТ_Узлы
		|		ПО ВТ_Контур.УзелИнформационнойБазы = ВТ_Узлы.Ссылка
		|		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_ЕстьУдаление КАК ВТ_ЕстьУдаление
		|		ПО (ИСТИНА)";
		
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПланОбмена", "ПланОбмена." + ИмяПланаОбмена);
	
	ЭтотУзел = ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена(ИмяПланаОбмена);
	Префикс = Константы.ПрефиксУзлаРаспределеннойИнформационнойБазы.Получить();
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("ЭтотУзел", ЭтотУзел);
	Запрос.УстановитьПараметр("КодЭтогоУзла", ЭтотУзел.Код);
	Запрос.УстановитьПараметр("НаименованиеЭтогоУзла", ЭтотУзел.Наименование);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Если Выборка.ОбновитьРеквизиты Тогда
			
			Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
			ЗаполнитьЗначенияСвойств(Запись, Выборка);
			Запись.Прочитать();
			Запись.КодУзла = ЭтотУзел.Код;
			Запись.ИмяУзла = ЭтотУзел.Наименование;
			Запись.КодУзлаКорреспондента = Выборка.Код;
			Запись.ИмяУзлаКорреспондента = Выборка.Наименование;
			Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
			Запись.Префикс = Префикс;
			Запись.Записать();
			
		ИначеЕсли Выборка.ДобавитьУзелВКонтур Тогда
			
			Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
			Запись.УзелИнформационнойБазы = Выборка.Ссылка;
			Запись.КодУзла = ЭтотУзел.Код;
			Запись.ИмяУзла= ЭтотУзел.Наименование;
			Запись.КодУзлаКорреспондента = Выборка.Код;
			Запись.ИмяУзлаКорреспондента = Выборка.Наименование;
			Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
			Запись.Префикс = Префикс;
			Запись.Записать();
			
		ИначеЕсли Выборка.УдалитьУзелИзКонтура Тогда
			
			Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
			ЗаполнитьЗначенияСвойств(Запись, Выборка);
			Запись.Прочитать();
			Запись.Удалить();
			
			УдалитьКоррУзел(Выборка.КодУзла, Выборка.КодУзлаКорреспондента);
			
		ИначеЕсли Выборка.УстановитьПоследнееОбновление Тогда
			
			Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
			ЗаполнитьЗначенияСвойств(Запись, Выборка);
			Запись.Прочитать();
			Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
			Запись.Записать();
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры 

Процедура ПроверитьЗацикливание(ИмяПланаОбмена, Режим = "ЗагрузкаКонтура") Экспорт
	
	ЭтотУзел = ПланыОбмена[ИмяПланаОбмена].ЭтотУзел();
	
	Запрос = Новый Запрос;
	Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Узлы.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Узлы.КодУзла КАК КодУзла,
		|	Узлы.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Узлы.ИмяУзла КАК ИмяУзла,
		|	Узлы.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента,
		|	Узлы.СинхронизацияУдалена КАК СинхронизацияУдалена,
		|	Узлы.ПоследнееОбновление КАК ПоследнееОбновление,
		|	Узлы.Префикс КАК Префикс,
		|	Узлы.Зацикливание КАК Зацикливание
		|ПОМЕСТИТЬ ВТ_Контур
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Узлы
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КонтурСинхронизации КАК КоррУзлы
		|		ПО Узлы.КодУзла = КоррУзлы.КодУзлаКорреспондента
		|			И Узлы.КодУзлаКорреспондента = КоррУзлы.КодУзла";
	
	Запрос.Выполнить();
			
	Если Режим = "ЗагрузкаКонтура" Тогда
		
		// Если зацикливание было раньше определено в другой базе, и эта база участвует в нем, 
		// то не устанавливаем признак зацикливания в этом узле

		Запрос.Текст = 
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	Контур.КодУзла КАК КодУзла
			|ИЗ
			|	ВТ_Контур КАК Контур
			|ГДЕ
			|	Контур.УзелИнформационнойБазы = НЕОПРЕДЕЛЕНО
			|	И Контур.КодУзлаКорреспондента = &КодУзла
			|	И Контур.Зацикливание";
		
		Запрос.УстановитьПараметр("КодУзла", ЭтотУзел.Код);
		
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			Возврат;
		КонецЕсли;
		
	КонецЕсли;
	
	//
	Запрос.Текст =
		"ВЫБРАТЬ
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Контур.ИмяУзла КАК ИмяУзла,
		|	Контур.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента
		|ИЗ
		|	ВТ_Контур КАК Контур
		|ИТОГИ
		|	МАКСИМУМ(ИмяУзла)
		|ПО
		|	КодУзла";
		
	КонтурСинхронизации = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	СписокУзлов = ПроверитьЗацикливаниеРекурсивно(КонтурСинхронизации, ЭтотУзел.Код);
	
	Если СписокУзлов = Неопределено Тогда
		СнятьПризнакЗацикливания();
	Иначе
		УстановитьПризнакЗацикливания(СписокУзлов);	
	КонецЕсли;
		
КонецПроцедуры  

Функция ЕстьЗацикливание() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ИСТИНА КАК ЕстьЗацикливание
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК КонтурСинхронизации
		|ГДЕ
		|	КонтурСинхронизации.Зацикливание";
	
	Результат = Запрос.Выполнить();
	
	Возврат Не Результат.Пустой();
	
КонецФункции

Функция УзелЗациклен(УзелИнформационнойБазы) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	КонтурСинхронизации.УзелИнформационнойБазы КАК УзелИнформационнойБазы
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК КонтурСинхронизации
		|ГДЕ
		|	КонтурСинхронизации.Зацикливание
		|	И (КонтурСинхронизации.КодУзла = &КодУзла
		|			ИЛИ КонтурСинхронизации.КодУзлаКорреспондента = &КодУзла)";
	
	Запрос.УстановитьПараметр("КодУзла", УзелИнформационнойБазы.Код);
	
	Результат = Запрос.Выполнить();
	
	Возврат Не Результат.Пустой();
	
КонецФункции

Функция ВсеЗацикленныеУзлыПредставление() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.ИмяУзла КАК ИмяУзла,
		|	Контур.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента
		|ПОМЕСТИТЬ ВТ_Контур
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.Зацикливание
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ВТ_Контур.ИмяУзла КАК ИмяУзла
		|ИЗ
		|	ВТ_Контур КАК ВТ_Контур
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ВТ_Контур.ИмяУзлаКорреспондента
		|ИЗ
		|	ВТ_Контур КАК ВТ_Контур";
	
	МассивУзлов = Новый Массив;
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		ИмяУзла = Выборка.ИмяУзла;
		МассивУзлов.Добавить(" - " + ИмяУзла);
	КонецЦикла;
	
	Возврат СтрСоединить(МассивУзлов, Символы.ПС);
	
КонецФункции

Функция БазаСПриостановленнойРегистрациейПредставление() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	Контур.ИмяУзла КАК ИмяУзла
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.Зацикливание";
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Возврат Выборка.ИмяУзла;
	Иначе
		Возврат "";
	КонецЕсли;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция ПроверитьЗацикливаниеРекурсивно(КонтурСинхронизации, НачальныйУзел, ТекущийУзел = "", Знач Родитель = "", Знач ЦепочкаУзлов = Неопределено) 
	
	Если ЦепочкаУзлов = Неопределено Тогда
		ЦепочкаУзлов = Новый СписокЗначений; 
	Иначе
		ЦепочкаУзлов.Добавить(ТекущийУзел);
	КонецЕсли;
	
	Если ТекущийУзел = "" Тогда
		ТекущийУзел = НачальныйУзел;
	КонецЕсли;
	
	Если ЦепочкаУзлов.НайтиПоЗначению(НачальныйУзел) <> Неопределено Тогда
		Возврат ЦепочкаУзлов;
	КонецЕсли;
		
	Отбор = Новый Структура("КодУзла", ТекущийУзел);
	Узлы = КонтурСинхронизации.Строки.НайтиСтроки(Отбор);
	
	Для Каждого Узел Из Узлы Цикл
		Для Каждого КоррУзел Из Узел.Строки Цикл
			
			Если КоррУзел.КодУзлаКорреспондента = Родитель Тогда // Обмен между двумя соседними узлами 
				Продолжить;
			КонецЕсли;
			
			Результат = ПроверитьЗацикливаниеРекурсивно(КонтурСинхронизации, НачальныйУзел, КоррУзел.КодУзлаКорреспондента, ТекущийУзел, ЦепочкаУзлов);
			
			Если Результат <> Неопределено Тогда
				Возврат Результат;
			КонецЕсли;
				
		КонецЦикла;
	КонецЦикла;
	
КонецФункции 

Процедура ОбновитьКонтурИзДерева(Дерево, ИмяПланаОбмена)
	
	МенеджерПланаОбмена = ПланыОбмена[ИмяПланаОбмена];
	ЭтотУзел = МенеджерПланаОбмена.ЭтотУзел();
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Контур.ИмяУзла КАК ИмяУзла,
		|	Контур.ИмяУзлаКорреспондента КАК ИмяУзлаКорреспондента,
		|	Контур.ПоследнееОбновление КАК ПоследнееОбновление,
		|	1 КАК КоличествоЗаписей
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.УзелИнформационнойБазы = НЕОПРЕДЕЛЕНО
		|ИТОГИ
		|	МАКСИМУМ(ПоследнееОбновление),
		|	СУММА(КоличествоЗаписей)
		|ПО
		|	КодУзла";
	
	КонтурСинхронизации = Запрос.Выполнить().Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Для Каждого УзелДерева Из Дерево.Строки Цикл
		
		// Не обновляем данные текущего узла
		Если УзелДерева.КодУзла = ЭтотУзел.Код Тогда
			Продолжить;
		КонецЕсли;
		
		Отбор = Новый Структура("КодУзла", УзелДерева.КодУзла);
		УзлыКонтура = КонтурСинхронизации.Строки.НайтиСтроки(Отбор);

		// Удаление устаревших записей
		Если УзлыКонтура.Количество() > 0 
			И УзлыКонтура[0].ПоследнееОбновление < УзелДерева.ПоследнееОбновление
			И УзлыКонтура[0].КоличествоЗаписей > 0 Тогда
			
			Для Каждого КоррУзелКонтура Из УзлыКонтура[0].Строки Цикл
				
				Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
				Запись.УзелИнформационнойБазы = Неопределено;
				Запись.КодУзла = КоррУзелКонтура.КодУзла;
				Запись.КодУзлаКорреспондента = КоррУзелКонтура.КодУзлаКорреспондента;
				Запись.Прочитать();
				Запись.Удалить();
				
			КонецЦикла;
			
		КонецЕсли;
		
		Если УзлыКонтура.Количество() = 0
			ИЛИ (УзлыКонтура[0].ПоследнееОбновление < УзелДерева.ПоследнееОбновление 
			И УзлыКонтура[0].КоличествоЗаписей > 0) Тогда
			
			Для Каждого КоррУзелДерева Из УзелДерева.Строки Цикл
				
				Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
				Запись.УзелИнформационнойБазы = Неопределено;
				Запись.КодУзла = УзелДерева.КодУзла;
				Запись.ИмяУзла = УзелДерева.ИмяУзла;
				Запись.КодУзлаКорреспондента = КоррУзелДерева.КодУзлаКорреспондента;
				Запись.ИмяУзлаКорреспондента = КоррУзелДерева.ИмяУзлаКорреспондента;
				Запись.ПоследнееОбновление = УзелДерева.ПоследнееОбновление;
				Запись.Префикс = УзелДерева.Префикс;
				Запись.Зацикливание = КоррУзелДерева.Зацикливание;
				Запись.Записать();
				
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЦикла;
			
КонецПроцедуры

Процедура ЗаменитьПрефиксы()
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	Контур1.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Контур1.КодУзла КАК КодУзла,
		|	Контур1.КодУзлаКорреспондента КАК КодУзлаКорреспондента,
		|	Контур2.КодУзла КАК НовыйКодУзлаКорреспондента
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур1
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КонтурСинхронизации КАК Контур2
		|		ПО Контур1.КодУзлаКорреспондента = Контур2.Префикс"; 
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
		ЗаполнитьЗначенияСвойств(Запись, Выборка);
		Запись.Прочитать();
		Запись.КодУзлаКорреспондента = Выборка.НовыйКодУзлаКорреспондента;
		Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
		Запись.Записать();
			
	КонецЦикла;
	
КонецПроцедуры

Процедура УстановитьПризнакЗацикливания(СписокУзлов = Неопределено)
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.УзелИнформационнойБазы <> НЕОПРЕДЕЛЕНО
		|	И Контур.КодУзлаКорреспондента В(&СписокУзлов)";
	
	Запрос.УстановитьПараметр("СписокУзлов", СписокУзлов);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
		ЗаполнитьЗначенияСвойств(Запись, Выборка);
		Запись.Прочитать();
		Запись.Зацикливание = Истина;
		Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
		Запись.Записать();
		
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьЗацикливание(Выборка.УзелИнформационнойБазы, Истина);
			
	КонецЦикла;
	
	ОбновитьПовторноИспользуемыеЗначения();
	
КонецПроцедуры

Процедура СнятьПризнакЗацикливания()
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур";
		
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
		ЗаполнитьЗначенияСвойств(Запись, Выборка);
		Запись.Прочитать();
		Запись.Зацикливание = Ложь;
		Запись.ПоследнееОбновление = УниверсальноеВремя(ТекущаяДатаСеанса());
		Запись.Записать();
		
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.УстановитьЗацикливание(Выборка.УзелИнформационнойБазы, Ложь, Ложь);
			
	КонецЦикла;
	
	ОбновитьПовторноИспользуемыеЗначения();
	
КонецПроцедуры

Процедура УдалитьКоррУзел(КодУзла, КодУзлаКорреспондента)
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Контур.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
		|	Контур.КодУзла КАК КодУзла,
		|	Контур.КодУзлаКорреспондента КАК КодУзлаКорреспондента
		|ИЗ
		|	РегистрСведений.КонтурСинхронизации КАК Контур
		|ГДЕ
		|	Контур.КодУзла = &КодУзла
		|	И Контур.КодУзлаКорреспондента = &КодУзлаКорреспондента";
	
	Запрос.УстановитьПараметр("КодУзла", КодУзлаКорреспондента);
	Запрос.УстановитьПараметр("КодУзлаКорреспондента", КодУзла);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		Запись = РегистрыСведений.КонтурСинхронизации.СоздатьМенеджерЗаписи();
		ЗаполнитьЗначенияСвойств(Запись, Выборка);
		Запись.Прочитать();
		Запись.Удалить();
	КонецЦикла;
	
КонецПроцедуры

Функция XMLБазоваяСхема()
	
	Возврат "http://www.1c.ru/SSL/Exchange/Message";
	
КонецФункции

#КонецОбласти